

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//leetcode_15:三数之和
//给你一个包含 n 个整数的数组nums，判断nums中是否存在三个元素 a，b，c ，使得a + b + c = 0 ？请你找出所有和为 0 且不重复的三元组。
//        注意：答案中不可以包含重复的三元组。
//        示例 1：
//        输入：nums = [-1,0,1,2,-1,-4]
//        输出：[[-1,-1,2],[-1,0,1]]
//        示例 2：
//        输入：nums = []
//        输出：[]
//        示例 3：
//        输入：nums = [0]
//        输出：[]
public class leetcode_15 {
//    标签：数组遍历
//    首先对数组进行排序，排序后固定一个数nums[i]，再使用左右指针指向nums[i]后面的两端，数字分别为nums[L]和nums[R]，
//    计算三个数的和 sum 判断是否满足为0，满足则添加进结果集
//    如果nums[i]大于0，则三数之和必然无法等于0，结束循环
//    如果nums[i] = nums[i−1]，则说明该数字重复，会导致结果重复，所以应该跳过
//    当 sum= 0 时，nums[L] ==nums[L+1] 则会导致结果重复，应该跳过，L++
//    当sum =0 时，nums[R] ==nums[R−1] 则会导致结果重复，应该跳过，R−−
//    时间复杂度：O(n^2)
public static List<List<Integer>> threeSum(int[] nums) {
    List<List<Integer>> ans = new ArrayList();
    int len = nums.length;
    if (nums == null || len < 3) return ans;
    Arrays.sort(nums); // 排序
    for (int i = 0; i < len; i++) {
        if (nums[i] > 0) break; // 如果当前数字大于0，则三数之和一定大于0，所以结束循环
        if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
        int L = i + 1;
        int R = len - 1;
        while (L < R) {
            int sum = nums[i] + nums[L] + nums[R];
            if (sum == 0) {
                ans.add(Arrays.asList(nums[i], nums[L], nums[R]));
                while (L < R && nums[L] == nums[L + 1]) L++; // 去重
                while (L < R && nums[R] == nums[R - 1]) R--; // 去重
                L++;
                R--;
            } else if (sum < 0) L++;
            else if (sum > 0) R--;
        }
    }
    return ans;
}
}
